home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1995 August: Tool Chest / Dev.CD Aug 95 TC / Dev.CD Aug 95 TC.toast / Tool Chest / Development Tools & Languages / Macintosh Common Lisp Related / User Contributions / zebu v3.3.3 (LALR parser) / doc / zebu.text < prev   
Encoding:
Text File  |  1994-09-12  |  14.8 KB  |  528 lines  |  [TEXT/ttxt]

  1.                 ZEBU -- AN LALR(1) PARSER SYSTEM IN SCHEME
  2.                                 Version .9
  3.  
  4.                 Copyright (C) 1989, by William M. Wells III
  5.                             All Rights Reserved
  6.         Permission is granted for unrestricted non-commercial use.
  7.  
  8.  
  9.  
  10.  
  11.  
  12.      INTRODUCTION
  13.  
  14.      ZEBU is a lalr(1) parser generator package.  It facilitates the
  15.      automatic construction of syntax driven processors within the
  16.      SCHEME [2] programming environment.  Zebu bears resemblance to
  17.      the UNIX program YACC [1].
  18.  
  19.      Zebu reads grammar files that contain the description of a
  20.      language as well as the actions to be taken as the language is
  21.      parsed.  The language is described by production rules, while the
  22.      actions are described by associated lambda expressions.
  23.  
  24.      Zebu generates parse table files which describe an lr parsing
  25.      machine that processes the specified language.
  26.  
  27.      Zebu has a parser driver component which processes the specified
  28.      language using the parse table file.
  29.  
  30.      A good discussion of lalr(1) parser generators and syntax
  31.      directed translation appears in PRINCIPLES OF COMPILER DESIGN
  32.      [3].
  33.  
  34.  
  35.  
  36.  
  37.      I.  Sample Session
  38.  
  39.      Zebu is best introduced by way of example.  The following is a
  40.      transcript of an interaction with Zebu.
  41.  
  42.           ;;; Zebu is used to generate the parse table file "ex1.tab"
  43.           ;;; from grammar file "ex1.grm"
  44.  
  45.           1 ]=> (compile-slr-grammar "ex1.grm" "ex1.tab")
  46.           reading grammar from ex1.grm, start symbols is: E
  47.           7 productions,  11 symbols
  48.           Dumping parse tables to ex1.tab
  49.           ;No value
  50.  
  51.           ;;; The resulting parse table file is loaded into Zebu's
  52.           ;;; parser driver:
  53.           1 ]=> (load-parse-tables "ex1.tab")
  54.           ;No value
  55.  
  56.           ;;; Zebu's parser driver is used to parse an expression
  57.           ;;; from the language described in grammar file "ex1.grm"
  58.  
  59.           1 ]=> (list-parser '(ned "+" jed))
  60.  
  61.  
  62.  
  63.  
  64.                                   -- 1 --
  65.  
  66.  
  67.  
  68.  
  69.  
  70.  
  71.           ;Value: (EXPRESSION (EXPRESSION (TERM (FACTOR NED)))
  72.             "+" (TERM (FACTOR JED)))
  73.  
  74.           1 ]=> (list-parser '(fred "+" ned "*" jed))
  75.           ;Value: (EXPRESSION (EXPRESSION (TERM (FACTOR FRED)))
  76.             "+" (TERM (TERM (FACTOR NED)) "*" (FACTOR JED)))
  77.  
  78.  
  79.  
  80.  
  81.      II. About Grammar Files
  82.  
  83.      This is the grammar file for the example above.
  84.  
  85.  
  86.           (E E "+" T)
  87.           (LAMBDA (EE PLUS TT) (LIST 'expression EE PLUS TT))
  88.  
  89.           (E T)
  90.           (LAMBDA (TT) (LIST 'expression TT))
  91.  
  92.           (T T "*" F)
  93.           (LAMBDA (TT TIMES F) (LIST 'term TT TIMES F))
  94.  
  95.           (T F)
  96.           (LAMBDA (F) (LIST 'term F))
  97.  
  98.           (F "(" E ")")
  99.           (LAMBDA (LP EE RP) (LIST 'factor LP EE RP))
  100.  
  101.           (F IDENTIFIER)
  102.           (LAMBDA (ID) (list 'factor id))
  103.  
  104.  
  105.  
  106.      The file contains alternating encodings of grammar productions
  107.      and associated actions to be performed at parsing time.
  108.  
  109.      The productions are encoded in scheme lists.  The first element
  110.      of the list is the left hand side of the production; the rest of
  111.      the list is the right hand side of the production.  Thus a
  112.      production which normally might be written as:
  113.  
  114.  
  115.           E -> E + T
  116.  
  117.      is encoded as:
  118.  
  119.           (E E "+" T)  .
  120.  
  121.      Grammar symbols may be written either as scheme symbols or scheme
  122.      strings.  For Zebu's parsers, tokens are classified according to
  123.      their relation to the grammar symbols in the sense of (equal?) .
  124.  
  125.      Zebu assumes that the start symbol of the grammar appears on the
  126.  
  127.  
  128.  
  129.  
  130.                                   -- 2 --
  131.  
  132.  
  133.  
  134.  
  135.  
  136.  
  137.      left hand side of the first production.
  138.  
  139.      The associated lambdas are applied during parsing.  As the lr
  140.      parser processes the input text it performs "reductions" using
  141.      the productions of the grammar.  When a reduction is performed,
  142.      the action (lambda) associated with the production is applied.
  143.  
  144.      The arguments to the lambdas arise in two ways.  The arguments to
  145.      the lambda are in correspondence with the right hand side of the
  146.      production.  If an argument corresponds to a terminal grammar
  147.      symbol, then the parser driver supplies the instantiation of the
  148.      grammar symbol as seen by the tokenizer.  If an argument
  149.      corresponds to a non-terminal symbol, then the driver supplies
  150.      the result of the application of the lambda that is associated
  151.      with the production from which the non-terminal was reduced.
  152.      This is not as complicated as it sounds.  The value returned by
  153.      the parser is the value given by the application of the lambda
  154.      associated with the production which is used to do the final
  155.      reduction of the input text to the start symbol.
  156.  
  157.      The lambdas in the above example are arranged to construct a
  158.      parse tree corresponding to the parse of the input text.
  159.  
  160.      The lambdas may use side effects, if desired.  The sequencing of
  161.      the application of the lambdas is governed by the ordering of the
  162.      reduce operations of the lr parser driver.
  163.  
  164.      The lambdas are used only at parsing time, not table generation
  165.      time.  If the Zebu parser driver isn't going to be used, tables
  166.      may be built without supplying meaningful lambdas.  As far as
  167.      parse table construction is concerned, the lambdas may be
  168.      replaced with arbitrary scheme expressions as place holders (such
  169.      as #f).
  170.  
  171.      The format of Zebu's parse table files is described in the source
  172.      file dump.scm.
  173.  
  174.  
  175.  
  176.  
  177.  
  178.      III.  LALR(1) and SLR(1)
  179.  
  180.      Zebu has two parser generating algorithms. (COMPILE-SLR-GRAMMAR
  181.      ...) requires an slr(1) grammar, while (COMPILE-LALR1-GRAMMAR
  182.      ...) requires a lalr(1) grammar.
  183.  
  184.      Although all slr(1) languages are lalr(1), the reverse is not
  185.      true. (compile-slr-grammar ...) is faster than (compile-lalr1-
  186.      grammar ...) and so may be preferred if the language at hand is
  187.      slr(1).
  188.  
  189.      The example grammar file "ex6-2.grm" is an example of a grammar
  190.      which is lalr(1) but not slr(1).
  191.  
  192.  
  193.  
  194.  
  195.  
  196.                                   -- 3 --
  197.  
  198.  
  199.  
  200.  
  201.  
  202.  
  203.  
  204.  
  205.  
  206.  
  207.      IV.  Using Ambiguous Grammars
  208.  
  209.      A simple feature allows the Zebu system to be used with some
  210.      ambiguous grammars.
  211.  
  212.      If the variable ALLOW-CONFLICTS is true, then when conflicts
  213.      arise at table construction time, the system simply prefers the
  214.      actions already in the tables.  This feature works for the
  215.      "dangling else" problem.
  216.  
  217.      Here is an example of building parse tables for a "dangling else"
  218.      grammar:
  219.  
  220.           1 ]=> (set! allow-conflicts #t)
  221.           ;Value: ()
  222.           1 ]=> (compile-slr-grammar "dangelse.grm" "dangelse.tab")
  223.           reading grammar from dangelse.grm, start symbols is: S
  224.           4 productions,  7 symbols
  225.  
  226.           ACTION CONFLICT!!! -- state: 6  old entry: (5 s 2)
  227.           new entry: (5 r 2)
  228.           WARNING: continuing to build tables despite conflicts...
  229.           Will prefer old entry: (5 s 2)
  230.           Dumping parse tables to dangelse.tab
  231.           ;No value
  232.  
  233.           1 ]=> (load-parse-tables "dangelse.tab")
  234.  
  235.           ;Value: (("+" . 4) ("*" . 6) ("(" . 8) (")" . 9) (IDENTIFIER . 10))
  236.  
  237.           1 ]=> (list-parser '(i i a e a))
  238.  
  239.           ;;; Note that the tables "do the right thing" with the dangling
  240.           ;;; else construct. (The else is associated with the nearest
  241.           ;;; un-elsed if).
  242.  
  243.           ;Value: (I (I (A) E (A)))
  244.  
  245.      The reported action conflict is a "shift-reduce" conflict that
  246.      has been resolved in favor of shifting.
  247.  
  248.      When conflicts arise, it may be useful to use (PRINT-COLLECTION
  249.      #F) or (PRINT-COLLECTION #T) which dump the lr0 item sets (which
  250.      correspond to the states of the parser) in order to understand
  251.      the problem the parser is facing.  (See the source file
  252.      tables.l for details.)
  253.  
  254.      Obtaining useful parse tables from ambiguous grammars requires
  255.      care.  PRINCIPLES OF COMPILER DESIGN [2] has a good discussion
  256.      about using ambiguous grammars.
  257.  
  258.  
  259.  
  260.  
  261.  
  262.                                   -- 4 --
  263.  
  264.  
  265.  
  266.  
  267.  
  268.  
  269.  
  270.  
  271.  
  272.      V.  The Parser Driver and Tokenizers
  273.  
  274.      Zebu has two components: the parser generator (the bulk of the
  275.      code) and a lr parser driver (contained in the file driver.scm).
  276.      The parser generator is needed only when parse table files are
  277.      being generated.
  278.  
  279.      The parser driver is quite simple.  It contains a lr parsing
  280.      engine (LR-PARSE) which may be used with arbitrary user supplied
  281.      tokenizers.  (LR-PARSE) is configured using (LOAD-PARSE-TABLES).
  282.  
  283.      Two parsers are supplied which use (LR-PARSE).  (LIST-PARSER)
  284.      will parse a token stream appearing as a scheme list.  (READ-
  285.      PARSER) will parse a token stream gotten via the scheme function
  286.      (READ).
  287.  
  288.      For some applications, the scheme function (READ) may not be a
  289.      suitable tokenizer.  In these cases, a custom tokenizer should be
  290.      constructed for use with (LR-PARSE).
  291.  
  292.      The two parsers (LIST-PARSER) and (READ-PARSER) have special case
  293.      behavior on the terminal symbols NUMBER and IDENTIFIER.  If the
  294.      terminal symbol NUMBER is present in the grammar, then the token
  295.      classifier will categorize objects that satisfy the scheme
  296.      function (NUMBER?) as instances of the terminal symbol NUMBER.
  297.      Other objects which match terminal symbols in the grammar will be
  298.      categorized as such.  Otherwise objects will be categorized as
  299.      instances of the terminal symbol IDENTIFIER, if it is present in
  300.      the grammar.
  301.  
  302.  
  303.  
  304.      APPENDIX 1. Loading Zebu
  305.  
  306.      To load the Zebu system, first load the file Zebu.scm from the
  307.      directory where Zebu is stored:
  308.  
  309.           (load "...  /zebu.scm")
  310.  
  311.  
  312.      then use the function
  313.  
  314.           (load-zebu)
  315.  
  316.      to load Zebu.
  317.  
  318.  
  319.  
  320.      APPENDIX 2. Function Summary
  321.  
  322.           ;;; Load the zebu bootstrap file:
  323.           (load "...  /zebu.scm")
  324.  
  325.  
  326.  
  327.  
  328.                                   -- 5 --
  329.  
  330.  
  331.  
  332.  
  333.  
  334.  
  335.  
  336.           ;;; Load the Zebu system.
  337.           (load-zebu)
  338.  
  339.           ;;; Compile an slr(1) grammar:
  340.           (compile-slr-grammar <grammar file> <parse table file>)
  341.  
  342.           ;;; Compile an lalr(1) grammar:
  343.           (compile-lalr1-grammar <grammar file> <parse table file>)
  344.  
  345.           ;;; Load a parse table file into Zebu's parsing engine:
  346.           (load-parse-tables <parse-table-file>)
  347.  
  348.           ;;; Parse some tokens from a list:
  349.           (list-parser '< a list of tokens ... >)
  350.  
  351.           ;;; Parse some tokens from the scheme function (read)
  352.           ;;; (this will detect end of tokens at end of file or upon reading
  353.           ;;; the scheme symbol :eof
  354.           (read-parser)
  355.  
  356.  
  357.  
  358.      APPENDIX 3. Interactive Calculator Example
  359.  
  360.      Here is a sample session that demonstrates an interactive
  361.      calculator implemented with Zebu.
  362.  
  363.           ;;; Load up the parse table file describing the calculator.
  364.           1 ]=> (load-parse-tables "calc.tab")
  365.           ;Value: ((I . 4) (E . 5) (A . 6))
  366.  
  367.           ;;; Load the file containing the rest of the calculator.
  368.           1 ]=> (load "calc.scm")
  369.           ;Value: CALC
  370.  
  371.           ;;; Do some calc-ulating...
  372.           1 ]=> (calc)
  373.           ? 1 + 2 * 3 :
  374.           7
  375.           ? 5 -> jed :
  376.           5
  377.           ? jed :
  378.           5
  379.           ? 1 + 3 -> fred -> ned :
  380.           4
  381.           ? ned * jed :
  382.           20
  383.           ? :eof
  384.           Bye now.
  385.           ;No value
  386.  
  387.  
  388.      Here is the content of calc.scm:
  389.  
  390.  
  391.  
  392.  
  393.  
  394.                                   -- 6 --
  395.  
  396.  
  397.  
  398.  
  399.  
  400.  
  401.  
  402.  
  403.           (define bindings '())
  404.  
  405.           (define (calc)
  406.             (display "? ")
  407.             (read-parser))
  408.  
  409.  
  410.  
  411.      And here is the grammar file describing the calculator:
  412.  
  413.           ;;; This grammar and the associated lambdas define
  414.           ;;; a simple interactive calculator.
  415.  
  416.  
  417.           ;;; A session is a sequence of transactions with the user.
  418.           ;;; When we reduce by this production, we're all done.
  419.           (session transaction-sequence)
  420.           (lambda (ignore) (display "Bye now."))
  421.  
  422.           ;;; A transaction-sequence is a sequence of transactions separated
  423.           ;;; by colons
  424.           (transaction-sequence transaction-sequence transaction :)
  425.           (lambda (a b c) 'dont-care)
  426.  
  427.           ;;; There might be no transactions.
  428.           (transaction-sequence)
  429.           (lambda () 'not-used)
  430.  
  431.           ;;; When the parser carries out the reduction by this
  432.           ;;; production, it causes the value of the expression
  433.           ;;; to be printed, and a new prompt to be shown.
  434.  
  435.           (transaction expression)
  436.           (lambda (value) (display value) (newline) (display "? "))
  437.  
  438.  
  439.  
  440.           ;;; The assignment operator.  Store the built up value of
  441.           ;;; the expression under the identifier.  The id argument
  442.           ;;; to the lambda is supplied with the symbol seen in the
  443.           ;;; token stream.  The lambda arranges to store away the
  444.           ;;; expression value under the symbol (in an alist).
  445.           (expression expression -> identifier)
  446.           (lambda (exp arrow id)
  447.             (set! bindings (cons `(,id . ,exp) bindings))
  448.             exp)
  449.  
  450.  
  451.           ;;; Implement addition:  When reduction occurs by this
  452.           ;;; production, we perform addition on the previously
  453.           ;;; built up sub expression values.
  454.           (expression expression + term)
  455.           (lambda (exp plus trm) (+ exp trm))
  456.  
  457.  
  458.  
  459.  
  460.                                   -- 7 --
  461.  
  462.  
  463.  
  464.  
  465.  
  466.  
  467.  
  468.           ;;; Similar to addition.
  469.           (expression expression - term)
  470.           (lambda (exp minus trm) (- exp trm))
  471.  
  472.           ;;; Arrange for typical distributive properties...
  473.           (expression term)
  474.           (lambda (x) x)
  475.  
  476.           ;;; Implement multiplication.  Like addition.
  477.           (term term * factor)
  478.           (lambda (trm mult fac) (* trm fac))
  479.  
  480.           ;;; Division.
  481.           (term term / factor)
  482.           (lambda (trm div fac) (/ trm fac))
  483.  
  484.           (term factor)
  485.           (lambda (x) x)
  486.  
  487.  
  488.           ;;; Do paren style grouping using < and > .
  489.           (factor < expression > )
  490.           (lambda (open-bracket exp close-bracket)
  491.             exp)
  492.  
  493.           ;;; The terminal symbol number.  When the parser driver
  494.           ;;; applies this lambda it supplies the value of the number
  495.           ;;; as seen in the token stream.
  496.           (factor number)
  497.           (lambda (x) x)
  498.  
  499.           ;;; The terminal symbol "identifier".  When the parser driver
  500.           ;;; applies this lambda, it supplies the symbol as seen in the
  501.           ;;; token stream.  The value associated with this name is looked
  502.           ;;; up by this lambda.
  503.           (factor identifier)
  504.           (lambda (id)
  505.             (cdr (assq id bindings)))
  506.  
  507.  
  508.  
  509.      REFERENCES
  510.  
  511.      [1] S.C. Johnson. YACC -- Yet Another Compiler Compiler.
  512.      Computing Science Technical Report 32, AT&T Bell Laboratories,
  513.      Murray Hill, NJ, 1975
  514.  
  515.      [2] J. Rees and W. Clinger (eds). Revised^3 Report on the
  516.      Algorithmic Language Scheme.  MIT AI Laboratory AI Memo 848a,
  517.      1986
  518.  
  519.      [3] A.V. Aho and J.D. Ullman. PRINCIPLES OF COMPILER DESIGN,
  520.      Addison Wesley 1979
  521.  
  522.  
  523.  
  524.  
  525.  
  526.                                   -- 8 --
  527.  
  528.